<script setup lang="ts">
import { ref, watch, computed, markRaw, shallowRef } from 'vue';
import type { Component, DefineComponent, ComponentPublicInstance } from 'vue';
import StandardPageItem1 from './components/StandardPageItem1.vue';
import StandardPageItem2 from './components/StandardPageItem2.vue';
import StandardPageItem3 from './components/StandardPageItem3.vue';

interface TabsConfig {
  /**
   * 标签名称，用于显示
   */
  label: string;
  /**
   * 标签值，用于判断，也作为唯一标识，用于辅助当前标签页下的数据存储
   */
  value: string;
  /**
   * 标签对应的组件
   */
  component: Component | DefineComponent;
  /**
   * 标签下的数据数量，用于显示在标签名称后面
   * 一种典型的应用场景是：位于标签右上角的数字提示气泡
   */
  number?: number;
}
const tabsConfig = ref<TabsConfig[]>([
  { label: 'tab1', value: 'TAB_ONE', component: markRaw(StandardPageItem1) },
  { label: 'tab2', value: 'TAB_TWO', component: markRaw(StandardPageItem2) },
  { label: 'tab3', value: 'TAB_THREE', component: markRaw(StandardPageItem3), number: 12 }
]);

interface Props {
  defaultActiveIndex?: number;
}
const props = withDefaults(defineProps<Props>(), {
  defaultActiveIndex: 0
});

// 使用 computed 自动生成 componentMap
const componentMap = computed(() => {
  return tabsConfig.value.reduce(
    (acc, tab) => ({
      ...acc,
      [tab.value]: tab.component
    }),
    {} as Record<string, Component | DefineComponent>
  );
});

const getValidIndex = (index: number, max: number) => {
  if (index < 0) return 0;
  if (index >= max) return max - 1;
  return index;
};

// 生成有效的初始索引
const validIndex = computed(() => getValidIndex(props.defaultActiveIndex, tabsConfig.value.length));

// 使用类型推导来确保类型安全
type TabValue = (typeof tabsConfig.value)[number]['value'];
const activeName = shallowRef<TabValue>(tabsConfig.value[validIndex.value].value);
const activeTitle = computed(
  () => tabsConfig.value.find((tab) => tab.value === activeName.value)?.label || ''
);

// 通用组件引用类型
const currentComponent = shallowRef<ComponentPublicInstance | null>(null);

// 监听 tabsConfig 的变化，确保 activeName 始终有效
watch([tabsConfig, validIndex], ([newTabs, newIndex]) => {
  if (newTabs.length === 0) {
    // 处理没有标签的情况
    activeName.value = '';
    return;
  }
  const validValues = newTabs.map((tab) => tab.value);
  if (!validValues.includes(activeName.value)) {
    activeName.value = newTabs[newIndex].value;
  }
});

// 定义一个类型守卫，用于判断组件是否具有 reloadPage 方法
function hasReloadPage(
  component: ComponentPublicInstance | null
): component is ComponentPublicInstance & { reloadPage: () => void } {
  return component !== null && 'reloadPage' in component;
}

// 注意，最好在组件中定义 reloadPage 方法，用于刷新页面
const handleClick = () => {
  if (hasReloadPage(currentComponent.value)) {
    currentComponent.value.reloadPage(); // 类型安全
  }
};
</script>

<template>
  <div class="h-full overflow-y-auto bg-white">
    <el-tabs v-model="activeName" class="px-5 pt-5 tabs-custom" @tab-click="handleClick">
      <el-tab-pane
        v-for="item in tabsConfig"
        :key="item.value"
        :label="item.label"
        :name="item.value"
      >
        <template #label>
          <div>{{ item.label }}</div>
          <div
            v-if="item.number"
            class="absolute flex items-center justify-center px-1 text-xs font-normal text-white bg-red-500 rounded-full top-0.5 -right-5 shadow-around"
          >
            {{ item.number }}
          </div>
        </template>
      </el-tab-pane>
    </el-tabs>
    <component
      :is="componentMap[activeName as keyof typeof componentMap]"
      ref="currentComponent"
      :tabValue="activeName"
      :tabTitle="activeTitle"
    />
  </div>
</template>

<style lang="scss" scoped>
:deep(.tabs-custom) {
  .el-tabs__item {
    font-size: 16px;
    font-weight: bold;
  }
  .el-tabs__content {
    overflow: initial;
  }
}
</style>
